<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/remarkable/1.7.4/remarkable.min.js"
            integrity="sha512-l+uDGrLLDzqHmCZy8IG4bDcFIIF3ps/YZDwaI6cgWmI1Dpz3dQ5chRvBBXGaLwKbSzqTtozKPNnM7XU74w059g=="
            crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!--    <script src="https://cdnjs.cloudflare.com/ajax/libs/remarkable/2.0.1/remarkable.min.js"-->
<!--            integrity="sha512-skYYbQHAuOTpeJTthhUH3flZohep8blA+qjZOY0VqmfXMDiYcWxu29F5UbxU4LxaIpGkRBk+3Qf8qaXfd9jngg=="-->
<!--            crossorigin="anonymous" referrerpolicy="no-referrer"></script>-->
    <title>React</title>
</head>

<body>
<div>
    <div id="example1"></div>
    <div id="example2"></div>
    <div id="example3"></div>
    <div id="example4"></div>
    <div id="example5"></div>
</div>
</body>
<script type="text/babel">
    ReactDOM.render(<h1>Hello, world!</h1>, document.getElementById("example1"));

    // 简单组件
    class HelloMessage extends React.Component {
        render() {
            return <div>Hello {this.props.name}</div>;
        }
    }

    ReactDOM.render(<HelloMessage name="Madison"/>, document.getElementById("example2"));

    /*
        有状态组件
        除了使用外部数据（通过 this.props 访问）以外，组件还可以维护其内部的状态数据（通过 this.state 访问）。
        当组件的状态数据改变时，组件会再次调用 render() 方法重新渲染对应的标记。
    */
    class Timer extends React.Component {
        constructor(props) {
            super(props);
            this.state = {seconds: 0};
        }

        tick() {
            this.setState(state => ({
                seconds: state.seconds + 1
            }));
        }

        componentDidMount() {
            console.log('componentDidMount')
            this.interval = setInterval(() => this.tick(), 1000);
        }

        componentWillUnmount() {
            console.log('componentWillUnmount');
            clearInterval(this.interval);
        }

        render() {
            return (
                <div>
                    Seconds: {this.state.seconds}
                </div>
            );
        }
    }

    ReactDOM.render(<Timer/>, document.getElementById('example3'));

    /*
        应用
        使用 props 和 state，我们可以创建一个简易的 Todo 应用。
        在示例中，我们使用 state 来保存现有的待办事项列表及用户的输入。
        尽管事件处理器看似被内联地渲染，但它们其实只会被事件委托进行收集和调用。
    */
    class TodoApp extends React.Component {
        constructor(props) {
            super(props);
            this.state = {items: [], text: ''};
            this.handleChange = this.handleChange.bind(this);
            this.handleSubmit = this.handleSubmit.bind(this);
        }

        render() {
            return (
                <div>
                    <h3>TODO</h3>
                    <TodoList items={this.state.items}/>
                    <form onSubmit={this.handleSubmit}>
                        <label htmlFor="new-todo">What needs to be done?</label>
                        <input id="new-todo" onChange={this.handleChange} value={this.state.text}/>
                        <button>Add #{this.state.items.length + 1}</button>
                    </form>
                </div>
            );
        }

        handleChange(e) {
            this.setState({text: e.target.value})
        }

        handleSubmit(e) {
            e.preventDefault()
            if (this.state.text.length === 0) {
                return
            }
            const newItem = {
                text: this.state.text,
                id: Date.now()
            };
            this.setState(state => ({items: state.items.concat(newItem), text: ''}))
        }
    }

    class TodoList extends React.Component {
        render() {
            return (
                <ul>{this.props.items.map(item => (<li key={item.id}>{item.text}</li>))}</ul>
            )
        }
    }

    ReactDOM.render(<TodoApp/>, document.getElementById('example4'))

    /*
        在组件中使用外部插件
        React 允许你结合其他框架或库一起使用。
        示例中使用了一个名为 remarkable (https://github.com/jonschlinkert/remarkable) 的外部 Markdown 库。
        它可以实时转换 <textarea> 里的内容。
    */

    class MarkdownEditor extends React.Component {

        constructor(props) {
            super(props);
            this.md = new Remarkable();
            this.handleChange = this.handleChange.bind(this);
            this.state = {value: 'Hello, **world**!'};
        }

        handleChange(e) {
            this.setState({value: e.target.value});
        }

        getRawMarkup() {
            return {__html: this.md.render(this.state.value)};
        }

        render() {
            return (
                <div className="MarkdownEditor">
                    <h3>Input</h3>
                    <label htmlFor="markdown-content">Enter some markdown</label>
                    <textarea id="markdown-content" onChange={this.handleChange}
                              defaultValue={this.state.value}></textarea>
                    <h3>Output</h3>
                    <div className="content" dangerouslySetInnerHTML={this.getRawMarkup()}></div>
                </div>
            )
        }
    }

    ReactDOM.render(<MarkdownEditor/>, document.getElementById('example5'))
</script>

</html>
